home *** CD-ROM | disk | FTP | other *** search
- real p0[], p1[]; ** for plotter
- real generalData[];
- real saveMean,saveArg; ** for dialog parameters when inputs used.
- integer mySeed, tempSeed;
- integer numData; ** found in solveGeneral()
- integer argK;
- integer oneInValid, twoInValid; ** tests for input connectors being used
- integer sending;
- real values[], plotArray[], timeArray[]; ** for distribution plot
-
- constant numMax is 50; // size of data table (general)
-
- ** This block generates random numbers
- ** Copyright © 1989-1992 by Imagine That, Inc.
- ** All Rights Reserved.
- ** Extend Generic Library, Input Random Number block; Alfy Riddle
- ** modified 2/5/92 JSL extensively modified for V2.0
- ** 9/1/92 BD modified Erlang
- ** 9/28/92 JSL added * 2.0 & factorB
- ** 9/30/92 JSL removed second get and setSeed from stepped
- ** 9/30/92 JSL reverted solveGeneral to 1.1 code.
- ** 2/16/93 JSL changed nummax to 50
- ** 5/4/93 JSL generate a number during initSim
- ** 10/14/93 PEH changed uniform real and intergers
- ** 1/17/94 JSL added tempSeed
- ** 1/26/94 DJK added triangular distribution
- ** 2/14/94 DJK modified trace and report
- ** 3/10/94 DJK added block label to report & trace
-
- ** Distributions from Pritsker, Intro to Simulation & SLAM II
- ** Carroll, Simulation using Personal Computers
- ** and Gordon, System Simulation
-
-
- Procedure sortFcn()
- {
- integer i, numIn, x, y;
- real temp0, temp1;
-
- ** find the number of data points
- if( noValue( data[0][0] ) )
- return;
-
- i=0;
- while( i<numMax && !noValue(data[i][0]) ) ** count Y values
- i++;
- numIn = i;
-
- for (x=0;x<numIn;x++)
- for (y=x+1;y<numIn;y++)
- if(data[y][0] < data[x][0])
- {
- temp0 = data[y][0];
- temp1 = data[y][1];
- data[y][0] = data[x][0];
- data[y][1] = data[x][1];
- data[x][0] = temp0;
- data[x][1] = temp1;
- }
- }
-
-
- ** these first three procedures are for the General distribution
- Integer getNumIn()
- {
- integer i, numIn;
-
- i=0;
-
- ** find the number of data points
- if( noValue( data[0][0] ) )
- {
- userError("No data to count in block number "+MyBlockNumber());
- abort;
- }
-
- while( i<numMax && !noValue(data[i][0]) ) ** count Y values
- i++;
- numIn = i;
-
- if( stepped ) ** check for last two probabilities equal
- {
- ** IF the user is not interpolating and
- ** the last two probabilities are not the same,
- ** THEN we do not have a clear definition of a bin,
- ** so we ASSUME a bin the same size as the last one
- ** and add it to the list of points.
-
- if( realAbs( data[numIn-1][1]-data[numIn-2][1]) > 1.0e-15 )
- {
- data[numIn][1] = data[numIn-1][1];
- data[numIn][0] = 2*data[numIn-1][0] - data[numIn-2][0];
- numIn++;
- }
- }
-
- return( numIn);
- }
-
-
- Procedure solveGeneral()
- {
- integer i;
- real factorA, factorB;
-
- ** this takes the density function (user input)
- ** turns it into a cumulative distribution function
- ** -> generalData[]
- ** and scales the result to be a true CDF
-
- numData = getNumIn();
-
- ** would be best to sort the PDF ascending here
- ** this will give fastest search later on
-
- ** "integrate" the PDF -> CDF
-
- makeArray(generalData, numMax);
-
- for (i = 0; i < numMax; i++)
- generalData[i] = 1.0;
-
- if( interpolate ) ** integrate trapezoidally
- {
- generalData[0] = 0.0;
-
- for( i=1; i< numData; i++ )
- {
- generalData[i] = generalData[i-1] +
- 0.5 * (data[i][1]+data[i-1][1]) * (data[i][0]-data[i-1][0]);
- }
- }
- else if( stepped ) ** sum the probabilities * binWidths
- {
- generalData[0] = 0.0;
-
- for( i=1; i< numData; i++ )
- {
- generalData[i] = generalData[i-1] + data[i-1][1] * (data[i][0] - data[i-1][0]);
- }
- }
- else ** discrete
- {
- generalData[0] = data[0][1];
-
- for( i=1; i< numData; i++ )
- generalData[i] = generalData[i-1] + data[i][1];
- }
-
- for( i=0; i< numData; i++ )
- {
- data[i][1] *= 1.0 / generalData[numData-1];
- generalData[i] /= generalData[numData-1];
- }
- }
-
-
- Real findGen(real val)
- {
- integer i;
- real result, slope, temp;
-
- ** first we find the bin of the data table (and CDF)
- ** this random variable corresponds to.
- ** Since the cumulative distribution function (CDF)
- ** varies from 0 to 1 we can use a 0->1 real
- ** random number to access our density function
- ** VAL is assumed >= 0 and < 1
-
- i = 0;
- slope = 0;
-
- while( val > generalData[i] ) ** find bin
- {
- i++;
- }
-
- if( i > 0 )
- {
- if( interpolate ) ** since linear slope in PDF, analytic eqn found
- {
- slope = (Data[i][1]-Data[i-1][1]) / (data[i][0]-data[i-1][0]);
-
- if (realAbs(slope) < 1e-10) ** slope to zero, NaN result
- slope = 1e-10; ** removes singularity at zero
-
- if( data[i][0] - data[i-1][0] == 0 ) ** interpolated fixed
- {
- userError("Probability Range values in rows "+i+" and "+(i+1)+" are the same.");
- abort;
- }
-
- temp = sqrt(data[i-1][1]^2 + 2.0*slope*(val-generalData[i-1]));
- result = (-data[i-1][1] + slope*data[i-1][0] + temp)/slope;
-
- }
- else if( stepped ) ** stepped
- {
- result = randomReal() * (data[i][0]-data[i-1][0])
- + data[i-1][0];
- }
- else
- result = data[i][0];
- }
- else
- result = data[0][0];
-
- return(result);
- }
-
-
- Real CalcValue() ** for distribution plot
- {
- real value, temp, min, max;
- integer i;
-
- tempSeed = RandomGetSeed();
- RandomSetSeed(mySeed);
- if( ranInt ) ** uniform integer
- value = floor(randomReal()*(0.9999999999999+argDist-meanDist)+meanDist);
- else if( ranReal )
- value = (argDist-meanDist)*randomReal()+meanDist;
- else if( norm )
- value = gaussian(meanDist, argDist);
- else if( binomial ) ** 11/28/90 BD Binomial bug workaround
- value = RealAbs(DBinomial(meanDist, argDist)); ** take ABS value
- else if( poisson )
- value = DPoisson(meanDist);
- else if( lognormal )
- value = DLogNormal(meanDist, argDist);
- else if( expo )
- value = DExponential(1.0/meanDist);
- else if( general )
- value = findGen( randomReal() );
- else if( erlang )
- {
- ** see Pritsker page714, note Pritsker's E{erlang}=U*K
-
- temp = 1.0;
- for( i=0;i<argK;i++ )
- {
- value = RandomReal(); // from 0.0 to 0.99999....
-
- if (value == 0.0) // if exactly zero, substitute 1e-3
- value = 1.0e-3; // zero breaks erlang
-
- temp *= value;
- }
-
- value = - meanDist * log(temp)/argDist;
- }
- else if( weibull ) // Pritsker p715
- value = meanDist*(-log(randomReal()+1.e-6))^(1.0/argDist);
- else if( hyper )
- {
- ** see Gordon, page 156, Note Gordon's E{hyper}=T
-
- if( randomReal() < argDist ) ** rate = 1/mean
- value = DExponential(2.0*argDist/meanDist);
- else
- value = DExponential(2.0*(1.0-argDist)/meanDist);
- }
- else if (triag) // DJK 12/1/93 - triangular distribution
- {
- temp = randomReal(); // calc 0,1 random variable
- min = meanDist; // get the minimum
- max = argDist; // get the maximum
- if(mode < min || mode > max) // if the mode is out of range -> abort
- {
- {
- Usererror("Most likely value is not between max and min for triangular distribution in Input Random Number block "+myBlockNumber()+".");
- abort;
- }
- }
-
- if(temp <= ((mode - min)/(max-min))) // if on the left side of mode
- value = min + Sqrt((mode-min)*(max-min)*temp);
- if(temp > ((mode - min)/(max-min))) // if on the right side of mode
- value = max - Sqrt((max-mode)*(max-min)*(1-temp));
- }
-
- mySeed = randomGetSeed();
- RandomSetSeed(tempSeed);
-
- return(value);
- }
-
-
- procedure getNumber()
- {
- ** let users have time varying statistics
- if( oneInValid )
- meanDist = oneIn;
-
- if( twoInValid )
- argDist = twoIn;
-
- DistOut = CalcValue(); ** for distribution plot
-
- ** sysGlobal2 is the file reference number for the DEBUG TRACE
- if( sysGlobal2 != 0.0 ) ** 0 is error, check for open file for TRACE
- {
- // template for report: |BLOCK NAME *****************|block number |BLOCK NUMBER*******
- fileWrite(sysGlobal2,"Input Random Number block number "+MyBlockNumber()+". Current Time:"+currentTime+".","",True);
- if(getBlockLabel(myBlockNumber()) != "")
- fileWrite(sysGlobal2,"Block Label: "+getBlockLabel(myBlockNumber()),"",True);
- if( oneInValid )
- fileWrite(sysGlobal2," Parameter 1 = "+oneIn,"",True);
-
- if( twoInValid )
- fileWrite(sysGlobal2," Parameter 2 = "+twoIn,"",True);
-
- fileWrite(sysGlobal2," Output = "+distOut,"",True);
- fileWrite(sysGlobal2," ","",True);
- }
- }
-
-
- on DistOut
- {
- if (sending)
- return;
-
- // if sysGlobalint9 == TRUE, msg came from plotter
- // and if so, we should not recalculate the random number,
- // instead we should just let the connector value ride.
-
- if (!sysGlobalint9)
- {
- sending = TRUE;
- if (oneInValid)
- sendMsgToOutputs(oneIn);
- if (twoInValid)
- sendmsgToOutputs(twoIn);
- sending = FALSE;
- getNumber();
- }
- }
-
-
- ** This message occurs for each step in the simulation.
- on Simulate
- {
- getNumber();
- }
-
-
- integer DataIsBad() ** for distribution plot
- {
- real temp;
-
- if( ranInt or ranReal )
- if( meanDist > argDist ) ** swap if user input backwards
- {
- temp = meanDist;
- meanDist = argDist; ** the "a"
- argDist = temp; ** the "b"
- }
-
- if( expo OR poisson OR lognormal)
- if( meanDist < 1.0e-15 )
- {
- userError("Mean must be greater than zero in Input Random Number block number "+MyBlockNumber());
- return(TRUE);
- }
-
- if( binomial )
- if( (meanDist < 1.0e-15) OR (meanDist > 1) )
- {
- userError("Probability must be between 0 and 1 in Input Random Number block number "+MyBlockNumber());
- return(TRUE);
- }
-
- if ( hyper AND (argDist < 0.0 OR argDist > 1.0))
- {
- userError("S must be between 0 and 1 in Input Random Number block number "+MyBlockNumber());
- return(TRUE);
- }
-
- return(FALSE); ** data is ok
- }
-
-
- ** If the dialog data is inconsistent for simulation, abort.
- on checkData
- {
- oneInValid = oneIn;
- twoInValid = twoIn;
-
- sysGlobal1 = 0.0; ** prevent false reports
- sysGlobal2 = 0.0; ** prevent false debugs
-
- if (DataIsBad()) ** for distribution plot
- abort;
- }
-
-
- procedure doInitSim() ** for distribution plot
- {
- sortFcn();
-
- if( general )
- solveGeneral();
- else if( erlang OR binomial )
- {
- argK = floor(argDist+0.5); ** nearest integer
- argDist = argK;
- }
-
- saveMean = meanDist; ** save dialog values in case inputs used
- saveArg = argDist; ** inputs write over dialog values
- }
-
-
- ** Initialize any simulation variables.
- on initSim
- {
- if (randomSeed == 0)
- mySeed = RandomGetSeed() + myBlockNumber()+1;
- else
- mySeed = randomSeed + myBlockNumber()+1;
-
- doInitSim(); ** for distribution plot
-
- if( getPassedArray(sysGlobal0, timeArray) )
- getSimulateMsgs(FALSE);
-
- sending = FALSE;
- getNumber();
- }
-
-
- string doName()
- {
- string results;
-
- if( expo )
- return "Exponential";
- else if( erlang )
- return "Erlang";
- else if( weibull )
- return "Weibull";
- else if( ranInt )
- return "Uniform Integer";
- else if( ranReal )
- return "Uniform Real";
- else if( norm )
- return "Normal";
- else if( general )
- return "General";
- else if( poisson )
- return "Poisson";
- else if( binomial )
- return "Binomial";
- else if( lognormal )
- return "LogNormal";
- else if( hyper )
- return "Hyperexponential";
- else if( triag )
- return "Triangular";
- }
-
-
- on endSim
- {
- ** sysGlobal1 is the file reference number for the TEXT REPORT
- if( sysGlobal1 != 0.0 ) ** 0 is error, check for open file for REPORT
- {
- // template for report: |BLOCK NAME *****************|block number |BLOCK NUMBER*******
- fileWrite(sysGlobal1,"Input Random Number block number "+MyBlockNumber(),"",True);
- if(getBlockLabel(myBlockNumber()) != "")
- fileWrite(sysGlobal1,"Block Label: "+getBlockLabel(myBlockNumber()),"",True);
- fileWrite(sysGlobal1," Function = "+doName(),"",True);
- if( general )
- {
- if( discrete )
- fileWrite(sysGlobal1," Discrete","",True);
- else if( stepped )
- fileWrite(sysGlobal1," Stepped","",True);
- else if( interpolate )
- fileWrite(sysGlobal1," Interpolated","",True);
- }
- fileWrite(sysGlobal1," Parameter 1 = "+meanDist,"",True);
- if( oneInValid )
- fileWrite(sysGlobal1," Parameter 1 input used","",True);
-
- fileWrite(sysGlobal1," Parameter 2 = "+argDist,"",True);
-
- if( twoInValid )
- fileWrite(sysGlobal1," Parameter 2 input used","",True);
-
- if(triag)
- fileWrite(sysGlobal1," Most Likely Value = "+mode,"",True);
-
- if( comments != "" )
- fileWrite(sysGlobal1," Comments = "+comments,"",True);
-
- fileWrite(sysGlobal1," ","",True);
- }
- }
-
-
- on createBlock
- {
- meanDist = 0.0;
- argDist = 1.0;
- expo = 0;
- erlang = 0;
- hyper = 0;
- weibull = 0;
- general = 0;
- ranInt = 0;
- ranReal = 1;
- norm = 0;
- poisson = 0;
- binomial = 0;
- lognormal = 0;
-
- discrete = 1;
- interpolate = 0;
- stepped = 0;
-
- NMembers = 200.0; ** for distribution plot
- }
-
-
- Procedure setText(string mReplace, string argReplace, string genReplace)
- {
- mText = mReplace;
- argText = argReplace;
- genText = genReplace;
- }
-
-
- on dialogOpen
- {
- if( weibull )
- {
- setText("Scale =","Shape =","For General only");
- }
- else if( hyper )
- {
- setText("Mean =","s =","For General only");
- }
- else if( ranInt )
- {
- setText("Min =","Max =","For General only");
- }
- else if( ranReal or triag)
- {
- setText("Min =","Max =","For General only");
- }
- else if( general )
- {
- setText("unused.","(unused)","General values =");
- }
- else if( binomial )
- {
- setText("Prob =","N =","For General only");
- }
- else if( norm OR lognormal )
- {
- setText("Mean =","Std Dev =","For General only");
- }
- else if( expo OR poisson )
- {
- setText("Mean =","(unused)","For General only");
- }
- else if( erlang )
- {
- setText("Mean =","k =","For General only");
- }
- else
- {
- setText("Mean =","Arg =","For General only");
- }
- }
-
-
- on weibull
- {
- setText("Scale =","Shape =","For General only");
- }
-
-
- on hyper
- {
- setText("Mean =","s =","For General only");
- }
-
-
- on erlang
- {
- setText("Mean =","k =","For General only");
- }
-
- on expo
- {
- setText("Mean =","(unused)","For General only");
- }
-
- on binomial
- {
- setText("Prob =","N =","For General only");
- }
-
- on poisson
- {
- setText("Mean =","(unused)","For General only");
- }
-
- on lognormal
- {
- setText("Mean =","Std Dev =","For General only");
- }
-
- on ranInt
- {
- setText("Min =","Max =","For General only");
- }
-
- on ranReal
- {
- setText("Min =","Max =","For General only");
- }
-
- on triag
- {
- setText("Min =","Max =","For General only");
- if(novalue(mode))
- {
- if(!novalue(meanDist) && !novalue(argDist))
- mode = (argDist - meanDist)/2 + meanDist;
- }
- }
-
-
- on norm
- {
- setText("Mean =","Std Dev =","For General only");
- }
-
- on general
- {
- setText("unused","(unused)","General values =");
- }
-
- on discrete
- {
- setText("(unused)","(unused)","General values=");
- general = TRUE;
- }
-
- on stepped
- {
- setText("(unused)","(unused)","General values=");
- general = TRUE;
- }
-
- on interpolate
- {
- setText("(unused)","(unused)","General values=");
- general = TRUE;
- }
-
-
- on data
- {
- if (!general)
- userError("The General distribution must be selected to use this table.");
- }
-
-
- on doPlot
- {
- integer i, numPlot;
- real pStart,pEnd;
- real pMax,pMin;
-
- sortFcn();
-
- solveGeneral();
-
- ** NOTE that the probability function may be interpolated
- ** (i.e. the probability is linearly interpolated
- ** between data points) or not. If it is
- ** not interpolated the plotted points must define
- ** each corner of the discrete bins (upper & lower
- ** bound). This means twice as many points are
- ** needed.
-
- if( interpolate )
- numPlot = numData;
- else if( stepped )
- numPlot = 2 * numData - 1;
- else ** discrete
- numPlot = 3 * numData;
-
- makeArray(p0, numPlot); ** set up all arrays
- makeArray(p1, numPlot);
-
- for( i=0;i<numData;i++ ) ** get values of function
- {
- if( interpolate)
- {
- p0[i] = data[i][0]; ** x coordinates
- p1[i] = data[i][1];
- }
- else if( stepped ) ** use twice as many points so rect bins defined
- {
- p0[2*i] = data[i][0]; ** x coordinates
- p1[2*i] = data[i][1];
-
- if( i < numData-1 ) ** odd number of points (skip last)
- {
- p0[2*i+1] = data[i+1][0]; ** x coordinates
- p1[2*i+1] = data[i][1];
- }
- }
- else ** discrete
- {
- p0[3*i] = data[i][0]; ** x coordinates
- p1[3*i] = 0.0;
- p0[3*i+1] = data[i][0]; ** x coordinates
- p1[3*i+1] = data[i][1];
- p0[3*i+2] = data[i][0]; ** x coordinates
- p1[3*i+2] = 0.0;
- }
- }
-
- pMax = 1; ** the use of ceil & floor gives integer data limits
- pMin = 0;
- pStart = p0[0];
- pEnd = p0[numPlot-1];
-
- installAxis(0, "", "Bin Range", FALSE, pStart,pEnd, "",
- 0, pMin, pMax, "", 0, 0.0, 0.0, blackpattern, blackcolor, numPlot);
-
- installArray(0, 0, "Range", p0, pStart,pEnd,
- numPlot, 0, blackPattern, redColor);
- installArray(0, 1, "Density", p1, pStart,pEnd,
- numPlot, 0, blackPattern, redColor);
-
- makeScatter(0,0);
-
- showPlot(0, "Probability Density");
- }
-
-
- on plotNMembers
- {
- real min, max, val, points, range, pOverM;
- integer imembers, ipoints, i, j;
-
- if (randomSeed == 0)
- mySeed = RandomGetSeed() + myBlockNumber();
- else
- mySeed = randomSeed + myBlockNumber();
-
- if (DataIsBad())
- abort;
-
- if (novalue(NMembers) or NMembers <= 2.0)
- {
- usererror("Enter positive value for N greater than 2 (try 200)");
- abort;
- }
-
- doInitSim(); ** for distribution plot
-
- ** plot the distribution
- makeArray(values, NMembers);
- min = 1e4000;
- max = -1e4000;
- iMembers = NMembers;
- for (i=0; i<iMembers; i++)
- {
- val = CalcValue();
-
- if (val < min)
- min = val;
- else if (val > max)
- max = val;
- values[i] = val;
- }
-
- if (min == 0.0)
- min = -0.01;
- else
- min = min-realabs(min*0.01);
-
- if (max == 0.0)
- max = 0.01;
- else
- max = max+realabs(max*0.01);
-
- range = max-min; ** correct for index
- points = 50.0;
- pOverM = 100.0/NMembers;
- iPoints = points;
- makeArray(plotArray, points);
- for (i=0; i<iPoints; i++)
- plotArray[i] = 0.0;
- for (i=0; i<iMembers; i++)
- {
- j = (values[i]-min)*points/range-0.5;
-
- if (j < 0)
- j = 0;
- if (j >= ipoints)
- j = ipoints-1;
- plotArray[j] += pOverM;
- }
-
- disposePlot(1);
- installAxis(1, "Distribution Plotter", "Member Value", FALSE, min, max,
- "Percent Members", FALSE, 0.0, 1.0, "", 0, 0.0, 0.0,
- blackpattern, blackcolor, ipoints);
- installArray(1, 0, "% Members", plotArray, min, max,
- ipoints, 0, blackPattern, cyanColor);
- plotSignalFormat(1, 0, 1, 0);
- autoscaley(1);
- showPlot(1, "Distribution Plotter");
- }